﻿#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <list>
#include <assert.h>
using namespace std;

////Args是一个模板参数包，args是一个函数形参参数包
////声明一个参数包Args...args，这个参数包中可以包含0到任意个模板参数。
//template <class ...Args>
//void ShowList(Args... args) {
//	cout << sizeof...(args) << endl;//打印参数个数
//}

////解析方式一
//void _ShowList() { cout << endl; }
//
//template <class T, class ...Args>
//void _ShowList(const T& val, Args... args) {
//	cout << val << " ";
//	_ShowList(args...);
//}
//
//template <class ...Args>
//void ShowList(Args... args) {
//	_ShowList(args...);
//}
////ShowList把参数包args传给了_ShowList，然后_ShowList解析参数包第一个参数，并打印1。
////然后递归调用解析参数包第二个参数，以此类推，打印完123后，继续解析，发现里面是0个参数，
////就不匹配void _ShowList(const T& val, Args... args)  而是更匹配void _ShowList()，最后打印一个换行结束。
//int main() {
//	ShowList(1);
//	ShowList(1, 2);
//	ShowList(1, 2, 3);
//	ShowList(1, 2.2, 'x', 3.3);
//	return 0;
//}


////解析方式二
//template <class T>
//void PrintArg(T t) {
//	cout << t << " ";
//}
////展开函数
//template <class ...Args>
//void ShowList(Args... args) {
//	//PrintArg(args)是展开参数包的，逗号表达式是为了顺序执行且返回最后一个值，
//	//就是展开参数包后再返回0。因为0才能去初始化数组，参数包的返回值(void)不能初始化数组。
//	int arr[] = { (PrintArg(args), 0)... };
//	cout << endl;
//}



//template <class T>
//int PrintArg(T t) {
//	cout << t << " ";
//	return 0;
//}
////展开函数
//template <class ...Args>
//void ShowList(Args... args) {
//	//数组开多大空间取决于参数包有几个参数
//	//有几个参数PrintArg就会调用几次
//	int arr[] = { PrintArg(args) };
//	cout << endl;
//}
//
//int main() {
//	ShowList(1);
//	ShowList(1, 'A');
//	ShowList(1, 'A', std::string("sort"));
//	return 0;
//}


//演示可变参数包使用场景
namespace bit {
	class string {
	public:
		typedef char* iterator;
		iterator begin() { return _str; }
		iterator end() { return _str + _size; }
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size) {
			cout << "string(char* str) -- 构造" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		// s1.swap(s2)
		void swap(string& s) {
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		// 拷贝构造
		string(const string& s) { //const左值引用既可以引用左值，也可以引用右值
			cout << "string(const string& s) -- 拷贝构造 深拷贝" << endl;
			string tmp(s._str);
			swap(tmp);
		}

		//移动构造
		string(string&& s) {
			cout << "string(string&& s) -- 移动构造" << endl;
			swap(s);//this：指向正在构造的临时对象（内存由编译器分配）
			//临时对象不新开空间
		}

		// 赋值重载
		string& operator=(const string& s) {
			cout << "string& operator=(string s) -- 赋值重载 深拷贝" << endl;
			//string tmp(s);
			//swap(tmp);
			if (this != &s) {
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}
		string& operator=(string&& s) {
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);
			return *this;
		}

		~string() {
			delete[] _str;
			_str = nullptr;
		}
		char& operator[](size_t pos) {
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(size_t n) {
			if (n > _capacity) {
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch) {
			if (_size >= _capacity) {
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		//string operator+=(char ch)
		string& operator+=(char ch) {
			push_back(ch);
			return *this;
		}
		const char* c_str() const { return _str; }
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0; // 不包含最后做标识的\0
	};
}

//int main() {
//	std::list<bit::string> lt;
//	bit::string s1("111");
//	//void emplace_back (Args&&... args);
//	//该场景下，push_back 和 emplace_back没区别
//	lt.push_back(s1);//拷贝构造 深拷贝
//	lt.push_back(move(s1));//移动构造
//	bit::string s2("111");
//	lt.emplace_back(s2);//拷贝构造 深拷贝
//	lt.emplace_back(move(s2));//移动构造
//
//	//再次插入
//	lt.push_back("xxx");//调用构造 和 移动构造
//	lt.emplace_back("xxx");//调用构造
//	//push_back 的声明是 void push_back(const T& val) 或 void push_back(T&& val)。
//	//"xxx" 是 const char* 类型，需要先构造一个临时 bit::string 对象。
//	//然后调用 push_back(T&& val)（临时对象是右值，触发移动构造）。
//
//	//emplace_back 的声明是 template <class... Args> void emplace_back(Args&&... args)。
//	//它直接将参数包 Args... 转发到 bit::string 的构造函数：
//	//对于 emplace_back("xxx")，Args 推导为 const char* 。
//	//直接在 list 的节点内存中调用 bit::string("xxx")，省去临时对象和移动操作。
//
//	return 0;
//}



//多参数场景
int main() {
	std::list<pair<bit::string, int>> lt;
	lt.push_back(make_pair("1111", 1));//构造 + 移动构造
	lt.emplace_back("2222", 2);//构造
	//行为	    push_back	                emplace_back
	//构造时机	先构造临时对象，再放入容器	直接在容器内构造
	//参数处理	必须构造完整对象传入	        接受参数包，延迟构造
	//效率	    可能有额外拷贝 / 移动	        更高效，避免临时对象
	return 0;
}